package com.sunyard.pcc.shiro.config;

import com.sunyard.pcc.common.shiro.ShiroUtils;
import com.sunyard.pcc.shiro.core.AuthRealm;
import com.sunyard.pcc.shiro.core.LoginLimitCredentialsMatcher;
import com.sunyard.pcc.shiro.core.RedisShiroSessionDAO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: Hewei
 * @Description:
 * @Date: Created in 15:41 2018/2/8
 */
@Configuration
@Slf4j
public class ShiroConfig {

    @Bean(value = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier(value = "securityManager") SecurityManager securityManager){
        log.info("set shiro filter");
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilter.setLoginUrl("/sys/login");
        //无权限时的跳转页面
        shiroFilter.setUnauthorizedUrl("/");

        //filter有顺序分别 因此用LinkedHashMap
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/swagger-resources/**", "anon");

        filterMap.put("/statics/**", "anon");
        //登录页对应url, 不加这行首次访问会调用doGetAuthenticationInfo
        filterMap.put("/sys/login", "anon");
//        filterMap.put("/sys/login.html", "anon");
        filterMap.put("/favicon.ico", "anon");
        filterMap.put("/captcha.jpg", "anon");
        filterMap.put("/**", "authc");//添加此句， 会为登陆时且在调用其他url时进行登录验证
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }



    @Bean(value = "securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm, @Qualifier(value = "sessionManager") SessionManager sessionManager){
        log.info("shiro securityManager is loaded");
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
//        shiro redis 设置 此项目中使用自定义redis用户存储
//        manager.setSessionManager(sessionManager);
        return manager;
    }

    @Bean(value = "sessionManager")
    public SessionManager sessionManager(RedisShiroSessionDAO redisShiroSessionDAO,
                                         @Value(value = "${sunyard.redis.open}") Boolean useRedis,
                                         @Value(value = "${sunyard.shiro.redis}") Boolean saveInRedis){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //设置session过期时间为1小时(单位：毫秒)，默认为30分钟
        sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        //如果开启redis且将session存入redis
        if (useRedis && saveInRedis){
            sessionManager.setSessionDAO(redisShiroSessionDAO);
        }
        return sessionManager;
    }


    /**
     *  自定义权限验证类
     * @param loginLimitCredentialsMatcher
     * @return
     */
    @Bean(name = "authRealm")
    public AuthRealm authRealm(@Qualifier(value = "loginLimitCredentialsMatcher") LoginLimitCredentialsMatcher loginLimitCredentialsMatcher){
        log.info("shiro realm is loaded");
        AuthRealm authRealm = new AuthRealm();
        authRealm.setCredentialsMatcher(loginLimitCredentialsMatcher);
        return authRealm;
    }


    /**
     * 默认密码校验器
     * @return
     */
    @Bean(value = "defaultCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName(ShiroUtils.HASH_ALGORITHM_NAME);//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(ShiroUtils.HASH_INTERATIONS);//散列的次数，比如散列两次，相当于 md5(md5(""));

        return hashedCredentialsMatcher;
    }


    /**
     * 自定义密码校验器
     * @return
     */
    @Bean(value = "loginLimitCredentialsMatcher")
    public LoginLimitCredentialsMatcher credentialsMatcher(){
        log.info("使用自定义密码校验器{}", "loginLimitCredentialsMatcher");
        LoginLimitCredentialsMatcher loginLimitCredentialsMatcher = new LoginLimitCredentialsMatcher();

        loginLimitCredentialsMatcher.setHashAlgorithmName(ShiroUtils.HASH_ALGORITHM_NAME);//散列算法:这里使用MD5算法;
        loginLimitCredentialsMatcher.setHashIterations(ShiroUtils.HASH_INTERATIONS);//散列的次数，比如散列两次，相当于 md5(md5(""));

        return loginLimitCredentialsMatcher;
    }





    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier(value = "securityManager") SecurityManager securityManager){
        log.info("shiro 权限配置");
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    @Bean( value = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


}
